﻿//-----------------------------------------------------------------------
// <copyright file="GeneralExtensions.cs" company="deixei.com">
//     Copyright (c) deixei.com. All rights reserved.
// </copyright>
// <author>Marcio Parente</author>
//---------------------------------------------------------------------
namespace Deixei.Web
{
    using Deixei;
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Text;
    using System.Web.Mvc;
    using System.Web.Mvc.Html;
    using System.Web.Routing;
    using System.Web.Script.Serialization;
    using System.Linq.Expressions;
    using Deixei.Domain;
    using System.Reflection;
    using System.ComponentModel.DataAnnotations;
    using System.Collections;

    /// <summary>
    /// General ASP.NET MVC Extensions
    /// </summary>
    public static class GeneralExtensions
    {
        public static HtmlHelper<TModel> Entity<TModel>(this HtmlHelper html)
        {
            return new HtmlHelper<TModel>(html.ViewContext, html.ViewDataContainer);
        }

        public static MvcHtmlString Copyright(this HtmlHelper htmlHelper, string title)
        {
            // <p>&copy; <%: DateTime.Now.Year %> - My ASP.NET MVC Application</p>
            // Copyright (c) deixei.com. All rights reserved.
            string text = string.Format(WebResources.Copyright, DateTime.Now.Year, title);
            return new TagBuilder("p").Text(text).ToHtmlString();
        }

        public static MvcHtmlString Link(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, string areaName = "")
        {
            return LinkExtensions.ActionLink(htmlHelper, linkText, actionName, controllerName, new { area = areaName }, null);
        }


        public static MvcHtmlString MenuItem(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, string areaName = "", bool isActive = false)
        {
            TagBuilder item = new TagBuilder("li");
            if ( isActive )
            {
                item.AddClass("active");
            }
            item.Html(htmlHelper.ActionLink(linkText, actionName, controllerName, new { area = areaName }, null).ToHtmlString());
            
            
            //TODO: item.AddClass("active");
            
            //<li class="active"><%: Html.ActionLink("Home", "Index", "Home"). %></li>
            return item.ToHtmlString();
        }

        public static MvcHtmlString MenuBar(this HtmlHelper htmlHelper, string activeAreaName = "", string activeControllerName = "")
        {
            // <ul id="nav">
            //<li class="active"><%: Html.ActionLink("Home", "Index", "Home") %></li>
            // <li><%: Html.ActionLink("About", "About", "Home") %></li>
            // <li><%: Html.ActionLink("Contact", "Contact", "Home") %></li>
            // </ul>

            TagBuilder item = new TagBuilder("ul");
            item.Attribute("id", "menu");
            item.AddClass("nav");

            switch ( activeAreaName )
            {
                case "Home":
                    item.Append(
                        htmlHelper.MenuItem("Home", "Index", "Home", activeAreaName, (activeControllerName == "Home")),
                        htmlHelper.MenuItem("About", "About", "Home", activeAreaName, ( activeControllerName == "Home" )),
                        htmlHelper.MenuItem("Contact", "Contact", "Home", activeAreaName, ( activeControllerName == "Home" ))
                    );

                    break;
                case "Demos":
                    item.Append(
                        htmlHelper.MenuItem("Bootstrap", "Components", "Bootstrap", activeAreaName, ( activeControllerName == "Bootstrap" ))
                    );
                    break;
                case "Admin":
                    item.Append(
                        htmlHelper.MenuItem("Portfolio", "Index", "Portfolio", activeAreaName, ( activeControllerName == "Portfolio" ))
                    );
                    break;
                case "CustomerService":
                    item.Append(
                        htmlHelper.MenuItem("Accounts", "Index", "Accounts", activeAreaName, (activeControllerName == "Accounts")),
                        htmlHelper.MenuItem("Cases", "Index", "Cases", activeAreaName, (activeControllerName == "Cases")),
                        htmlHelper.MenuItem("Contracts", "Index", "Contracts", activeAreaName, (activeControllerName == "Contracts")),
                        htmlHelper.MenuItem("Knowledge", "Index", "Knowledge", activeAreaName, (activeControllerName == "Knowledge")),
                        htmlHelper.MenuItem("Scheduling", "Index", "Scheduling", activeAreaName, (activeControllerName == "Scheduling"))
                    );
                    break;
                case "Sales":
                    item.Append(
                        htmlHelper.MenuItem("Customer", "Index", "Customer", activeAreaName, ( activeControllerName == "Customer" )),
                        htmlHelper.MenuItem("Leads", "Index", "Leads", activeAreaName, ( activeControllerName == "Leads" )),
                        htmlHelper.MenuItem("Opportunities", "Index", "Opportunities", activeAreaName, ( activeControllerName == "Opportunities" )),
                        htmlHelper.MenuItem("Pipeline", "Index", "Pipeline", activeAreaName, ( activeControllerName == "Pipeline" )),
                        htmlHelper.MenuItem("Planning", "Index", "Planning", activeAreaName, ( activeControllerName == "Planning" )),
                        htmlHelper.MenuItem("Timesavers", "Index", "Timesavers", activeAreaName, ( activeControllerName == "Timesavers" ))
                    );
                    break;

                case "MarcioParente":
                    item.Append(
                        htmlHelper.MenuItem("Home", "Index", "CV", activeAreaName, ( activeControllerName == "CV" )),
                        htmlHelper.MenuItem("Personal", "Personal", "CV", activeAreaName, ( activeControllerName == "CV" )),
                        htmlHelper.MenuItem("Occupational", "Occupational", "CV", activeAreaName, ( activeControllerName == "CV" )),
                        htmlHelper.MenuItem("Work", "Work", "CV", activeAreaName, ( activeControllerName == "CV" )),
                        htmlHelper.MenuItem("Education", "Education", "CV", activeAreaName, ( activeControllerName == "CV" )),
                        htmlHelper.MenuItem("Competences", "Competences", "CV", activeAreaName, ( activeControllerName == "CV" )),
                        htmlHelper.MenuItem("Information", "Information", "CV", activeAreaName, ( activeControllerName == "CV" )),
                        htmlHelper.MenuItem("Annexes", "Annexes", "CV", activeAreaName, ( activeControllerName == "CV" ))
                    );
                    break;
                default:
                    item.Append(
                        htmlHelper.MenuItem("Home", "Index", "Home"),
                        htmlHelper.MenuItem("Components Demos", "Components", "Bootstrap", "Demos"),
                        htmlHelper.MenuItem("MP CV", "Index", "CV", "MarcioParente"),
                        htmlHelper.MenuItem("Customer Sales", "Index", "Customer", "Sales"),
                        htmlHelper.MenuItem("About", "About", "Home"),
                        htmlHelper.MenuItem("Contact", "Contact", "Home"),
                        htmlHelper.MenuItem("Test", "Test", "Home"),
                        htmlHelper.MenuItem("Values", "Values", "Home"));
                    break;
            }


            return item.ToHtmlString();
        }

        /// <summary>
        /// Contents the title.
        /// </summary>
        /// <param name="htmlHelper">The HTML helper.</param>
        /// <returns>Content Title string</returns>
        public static string ContentTitle(this HtmlHelper htmlHelper)
        {
            return htmlHelper.ViewData["__contentTitle"] as string;
        }

        /// <summary>
        /// Contents the title.
        /// </summary>
        /// <param name="htmlHelper">The HTML helper.</param>
        /// <param name="title">The title.</param>
        public static void ContentTitle(this HtmlHelper htmlHelper, string title)
        {
            htmlHelper.ViewData["__contentTitle"] = title;
        }

        /// <summary>
        /// Pages the title.
        /// </summary>
        /// <param name="htmlHelper">The HTML helper.</param>
        /// <returns>Page Title</returns>
        public static string PageTitle(this HtmlHelper htmlHelper)
        {
            return htmlHelper.ViewData["__pageTitle"] as string;
        }

        /// <summary>
        /// Pages the title.
        /// </summary>
        /// <param name="htmlHelper">The HTML helper.</param>
        /// <param name="title">The title.</param>
        public static void PageTitle(this HtmlHelper htmlHelper, string title)
        {
            htmlHelper.ViewData["__pageTitle"] = title;
        }

        /// <summary>
        /// HTMLs the page title.
        /// </summary>
        /// <param name="htmlHelper">The HTML helper.</param>
        /// <returns>Html Page Title</returns>
        public static string HtmlPageTitle(this HtmlHelper htmlHelper)
        {
            string str = htmlHelper.PageTitle();
            if (!string.IsNullOrEmpty(str))
            {
                return str;
            }

            string str2 = htmlHelper.ContentTitle();
            if (!string.IsNullOrEmpty(str2))
            {
                return string.Format(CommonResources.PageTitleWithContent.FormatUI(new object[] { str2 }));
            }

            return CommonResources.PageTitle;
        }

        #region "Helper methods"

        
        /// <summary>
        /// Texts the specified tag builder.
        /// </summary>
        /// <param name="tagBuilder">The tag builder.</param>
        /// <param name="text">The text.</param>
        /// <returns>HTML Text Tag</returns>
        public static TagBuilder Text(this TagBuilder tagBuilder, string text)
        {
            CommonUtil.CheckForNull(tagBuilder, "tagBuilder");
            tagBuilder.SetInnerText(text);
            return tagBuilder;
        }

        /// <summary>
        /// To the HTML string.
        /// </summary>
        /// <param name="tagBuilder">The tag builder.</param>
        /// <returns>HTML String</returns>
        public static MvcHtmlString ToHtmlString(this TagBuilder tagBuilder)
        {
            return tagBuilder.ToHtmlString(TagRenderMode.Normal);
        }

        /// <summary>
        /// To the HTML string.
        /// </summary>
        /// <param name="tagBuilder">The tag builder.</param>
        /// <param name="renderMode">The render mode.</param>
        /// <returns>HTML String</returns>
        public static MvcHtmlString ToHtmlString(this TagBuilder tagBuilder, TagRenderMode renderMode)
        {
            CommonUtil.CheckForNull(tagBuilder, "tagBuilder");
            return MvcHtmlString.Create(tagBuilder.ToString(renderMode));
        }

        /// <summary>
        /// HTMLs the specified tag builder.
        /// </summary>
        /// <param name="tagBuilder">The tag builder.</param>
        /// <param name="html">The HTML.</param>
        /// <returns>Html Tag</returns>
        public static TagBuilder Html(this TagBuilder tagBuilder, string html)
        {
            CommonUtil.CheckForNull(tagBuilder, "tagBuilder");
            tagBuilder.InnerHtml = html;
            return tagBuilder;
        }

        /// <summary>
        /// Appends the specified tag builder.
        /// </summary>
        /// <param name="tagBuilder">The tag builder.</param>
        /// <param name="children">The children.</param>
        /// <returns>Append to HTML element</returns>
        public static TagBuilder Append(this TagBuilder tagBuilder, params object[] children)
        {
            CommonUtil.CheckForNull(tagBuilder, "tagBuilder");
            if (children.Length > 0)
            {
                StringBuilder builder = new StringBuilder(tagBuilder.InnerHtml ?? string.Empty);
                foreach (object obj2 in children)
                {
                    if (obj2 != null)
                    {
                        builder.Append(obj2.ToString());
                    }
                }

                tagBuilder.InnerHtml = builder.ToString();
            }

            return tagBuilder;
        }

        /// <summary>
        /// Appends the tag.
        /// </summary>
        /// <param name="tagBuilder">The tag builder.</param>
        /// <param name="tagName">Name of the tag.</param>
        /// <param name="tagAction">The tag action.</param>
        /// <returns>Append to HTML element</returns>
        public static TagBuilder AppendTag(this TagBuilder tagBuilder, string tagName, Action<TagBuilder> tagAction)
        {
            CommonUtil.CheckForNull(tagBuilder, "tagBuilder");
            TagBuilder builder = new TagBuilder(tagName);
            if (tagAction != null)
            {
                tagAction(builder);
            }

            tagBuilder.Append(new object[] { builder });
            return tagBuilder;
        }

        /// <summary>
        /// Attributes the specified tag builder.
        /// </summary>
        /// <param name="tagBuilder">The tag builder.</param>
        /// <param name="attributes">The attributes.</param>
        /// <returns>Attribute Tag</returns>
        public static TagBuilder Attribute(this TagBuilder tagBuilder, object attributes)
        {
            return tagBuilder.Attribute(attributes, true);
        }

        /// <summary>
        /// Attributes the specified tag builder.
        /// </summary>
        /// <param name="tagBuilder">The tag builder.</param>
        /// <param name="attributes">The attributes.</param>
        /// <param name="replaceExisting">if set to <c>true</c> [replace existing].</param>
        /// <returns>Attribute Tag</returns>
        public static TagBuilder Attribute(this TagBuilder tagBuilder, object attributes, bool replaceExisting)
        {
            CommonUtil.CheckForNull(tagBuilder, "tagBuilder");
            if (attributes != null)
            {
                RouteValueDictionary dictionary = new RouteValueDictionary(attributes);
                if (dictionary.ContainsKey("addClass"))
                {
                    tagBuilder.AddClass(dictionary["addClass"] as string);
                    dictionary.Remove("addClass");
                }

                tagBuilder.MergeAttributes<string, object>(dictionary, replaceExisting);
            }

            return tagBuilder;
        }

        /// <summary>
        /// Attributes the specified tag builder.
        /// </summary>
        /// <param name="tagBuilder">The tag builder.</param>
        /// <param name="attribute">The attribute.</param>
        /// <param name="attributeValue">The attribute value.</param>
        /// <returns>Attribute Tag</returns>
        public static TagBuilder Attribute(this TagBuilder tagBuilder, string attribute, string attributeValue)
        {
            return tagBuilder.Attribute(attribute, attributeValue, true);
        }

        /// <summary>
        /// Attributes the specified tag builder.
        /// </summary>
        /// <param name="tagBuilder">The tag builder.</param>
        /// <param name="attribute">The attribute.</param>
        /// <param name="attributeValue">The attribute value.</param>
        /// <param name="replaceExisting">if set to <c>true</c> [replace existing].</param>
        /// <returns>Attribute Tag</returns>
        public static TagBuilder Attribute(this TagBuilder tagBuilder, string attribute, string attributeValue, bool replaceExisting)
        {
            CommonUtil.CheckForNull(tagBuilder, "tagBuilder");
            CommonUtil.CheckStringForNullOrEmpty(attribute, "attribute");
            tagBuilder.MergeAttribute(attribute, attributeValue, replaceExisting);
            return tagBuilder;
        }

        /// <summary>
        /// Adds the class.
        /// </summary>
        /// <param name="tagBuilder">The tag builder.</param>
        /// <param name="cssClass">The CSS class.</param>
        /// <returns>Add Class to HTML element</returns>
        public static TagBuilder AddClass(this TagBuilder tagBuilder, string cssClass)
        {
            CommonUtil.CheckForNull(tagBuilder, "tagBuilder");
            tagBuilder.AddCssClass(cssClass);
            return tagBuilder;
        }

        #endregion




        #region "Json Island"

        /// <summary>
        /// Javas the script.
        /// </summary>
        /// <param name="htmlHelper">The HTML helper.</param>
        /// <param name="javaScript">The java script.</param>
        /// <returns>HTML String</returns>
        public static MvcHtmlString JavaScript(this HtmlHelper htmlHelper, string javaScript)
        {
            return MvcHtmlString.Create("<script type=\"text/javascript\">" + javaScript + "</script>");
        }

        public static MvcHtmlString JavaScript(this HtmlHelper htmlHelper, params object[] children)
        {
            TagBuilder wraper = new TagBuilder("script");
            wraper.Attribute("type", "text/javascript");

            foreach ( var childitem in children )
            {
                wraper.Append(childitem);
            }
            return wraper.ToHtmlString();
        }

        

        /// <summary>
        /// Jsons the island.
        /// </summary>
        /// <param name="htmlHelper">The HTML helper.</param>
        /// <param name="data">The data.</param>
        /// <returns>HTML String</returns>
        public static MvcHtmlString JsonIsland(this HtmlHelper htmlHelper, object data)
        {
            return htmlHelper.JsonIsland(data, (IDictionary<string, object>)null, 0);
        }

        /// <summary>
        /// Jsons the island.
        /// </summary>
        /// <param name="htmlHelper">The HTML helper.</param>
        /// <param name="data">The data.</param>
        /// <param name="htmlAttributes">The HTML attributes.</param>
        /// <returns>HTML String</returns>
        public static MvcHtmlString JsonIsland(this HtmlHelper htmlHelper, object data, IDictionary<string, object> htmlAttributes)
        {
            return htmlHelper.JsonIsland(data, htmlAttributes, 0);
        }

        /// <summary>
        /// Jsons the island.
        /// </summary>
        /// <param name="htmlHelper">The HTML helper.</param>
        /// <param name="data">The data.</param>
        /// <param name="htmlAttributes">The HTML attributes.</param>
        /// <returns>HTML String</returns>
        public static MvcHtmlString JsonIsland(this HtmlHelper htmlHelper, object data, object htmlAttributes)
        {
            return htmlHelper.JsonIsland(data, (IDictionary<string, object>)new RouteValueDictionary(htmlAttributes), 0);
        }

        /// <summary>
        /// Jsons the island.
        /// </summary>
        /// <param name="htmlHelper">The HTML helper.</param>
        /// <param name="data">The data.</param>
        /// <param name="htmlAttributes">The HTML attributes.</param>
        /// <param name="maxJsonLength">Length of the max json.</param>
        /// <returns>HTML String</returns>
        public static MvcHtmlString JsonIsland(this HtmlHelper htmlHelper, object data, IDictionary<string, object> htmlAttributes, int maxJsonLength)
        {
            TagBuilder builder = new TagBuilder("script");
            if ( htmlAttributes != null )
            {
                builder.MergeAttributes<string, object>(htmlAttributes);
            }

            JavaScriptSerializer serializer = new JavaScriptSerializer();
            if ( maxJsonLength > 0 )
            {
                serializer.MaxJsonLength = maxJsonLength;
            }

            builder.MergeAttribute("type", "application/json");
            builder.MergeAttribute("defer", "defer");
            builder.InnerHtml = serializer.Serialize(data);
            return MvcHtmlString.Create(builder.ToString());
        }

        /// <summary>
        /// Jsons the island.
        /// </summary>
        /// <param name="htmlHelper">The HTML helper.</param>
        /// <param name="data">The data.</param>
        /// <param name="htmlAttributes">The HTML attributes.</param>
        /// <param name="maxJsonLength">Length of the max json.</param>
        /// <returns>HTML Json Island</returns>
        public static MvcHtmlString JsonIsland(this HtmlHelper htmlHelper, object data, object htmlAttributes, int maxJsonLength)
        {
            return htmlHelper.JsonIsland(data, (IDictionary<string, object>)new RouteValueDictionary(htmlAttributes), maxJsonLength);
        }

        #endregion





        #region "Labels"

        

        internal static MvcHtmlString LabelHelper(HtmlHelper html, ModelMetadata metadata, string htmlFieldName, string labelText = null, IDictionary<string, object> htmlAttributes = null)
        {
            string resolvedLabelText = labelText ?? metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
            if ( String.IsNullOrEmpty(resolvedLabelText) )
            {
                return MvcHtmlString.Empty;
            }

            TagBuilder tag = new TagBuilder("label");
            tag.Attributes.Add("for", TagBuilder.CreateSanitizedId(html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(htmlFieldName)));
            tag.SetInnerText(resolvedLabelText);
            tag.MergeAttributes(htmlAttributes, replaceExisting: true);
            return new MvcHtmlString(tag.ToString(TagRenderMode.Normal));
        }

        #endregion
    }
}
